<!-- ToastNotifications.vue -->
<template>
  <div
    class="toast-container"
    :class="containerClass"
  >
    <div
      v-for="toast in processedToasts"
      :key="toast.id"
      class="toast"
      :class="[toast.type, toast.placement]"
      role="alert"
      @mouseenter="pauseAutoClose(toast)"
      @mouseleave="resumeAutoClose(toast)"
    >
      <div class="toast-icon">
        <i :class="getToastIcon(toast.type)"></i>
      </div>
      <div class="toast-content">
        <div class="toast-title">{{ toast.title }}</div>
        <div class="toast-message">{{ toast.message }}</div>
      </div>
      <button
        @click="emitRemove(toast.id)"
        class="toast-close"
        aria-label="关闭通知"
      >
        <i class="fas fa-times"></i>
      </button>
    </div>
  </div>
</template>

<script setup>
import { computed, watch, onUnmounted } from 'vue'

const props = defineProps({
  toasts: {
    type: Array,
    required: true,
    default: () => []
  },
  placement: {
    type: String,
    default: 'bottom-right',
    validator: (value) => [
      'top-right',
      'bottom-right'
    ].includes(value)
  },
  duration: {
    type: Number,
    default: 5000
  }
})

const emit = defineEmits(['remove'])

const processedToasts = computed(() => {
  return props.toasts.map(toast => ({
    ...toast,
    placement: toast.placement || props.placement,
    duration: toast.duration ?? props.duration
  }))
})

const containerClass = computed(() => ({
  [props.placement]: true,
  'has-toasts': processedToasts.value.length > 0
}))

const timers = new Map()

watch(
  () => [...props.toasts],
  (newToasts, oldToasts) => {
    const newIds = newToasts.map(t => t.id)
    const oldIds = oldToasts.map(t => t.id)

    // Handle added toasts
    newToasts
      .filter(t => !oldIds.includes(t.id))
      .forEach(toast => {
        if (toast.duration !== 0) {
          const timeoutId = setTimeout(() => {
            emit('remove', toast.id)
          }, toast.duration)
          timers.set(toast.id, timeoutId)
        }
      })

    // Handle removed toasts
    oldToasts
      .filter(t => !newIds.includes(t.id))
      .forEach(toast => {
        const timerId = timers.get(toast.id)
        if (timerId) {
          clearTimeout(timerId)
          timers.delete(toast.id)
        }
      })
  },
  { deep: true }
)

onUnmounted(() => {
  timers.forEach((timerId) => clearTimeout(timerId))
  timers.clear()
})

function getToastIcon(type) {
  const icons = {
    success: 'fas fa-check-circle',
    error: 'fas fa-times-circle',
    warning: 'fas fa-exclamation-triangle',
    info: 'fas fa-info-circle'
  }
  return icons[type] || 'fas fa-info-circle'
}

function emitRemove(id) {
  emit('remove', id)
}

function pauseAutoClose(toast) {
  const timerId = timers.get(toast.id)
  if (timerId) {
    clearTimeout(timerId)
    timers.delete(toast.id)
  }
}

function resumeAutoClose(toast) {
  if (toast.duration !== 0 && !timers.has(toast.id)) {
    const timeoutId = setTimeout(() => {
      emit('remove', toast.id)
    }, toast.duration)
    timers.set(toast.id, timeoutId)
  }
}
</script>

<style scoped>
.toast-container {
  position: fixed;
  right: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;

  z-index: 2000;
  max-width: 450px;
  pointer-events: none;
}

.toast-container.has-toasts {
  pointer-events: auto;
}

/* 位置配置 */
.toast-container.bottom-right {
  bottom: auto;
  top: 1rem;
}

.toast-container.top-right {
  top: 1rem;
  bottom: auto;
}

.toast {
  display: flex;
  align-items: flex-start;
  padding: 1rem;
  border-radius: 4px;
  background-color: var(--component-background);
  box-shadow: 0 4px 12px var(--shadow-color);
  pointer-events: auto;
  transition: transform 0.3s ease, opacity 0.3s ease;
}

/* 类型样式 */
.toast.success { border-left: 4px solid var(--success); }
.toast.error { border-left: 4px solid var(--error); }
.toast.warning { border-left: 4px solid var(--warning); }
.toast.info { border-left: 4px solid var(--primary); }

/* 图标颜色 */
.toast.success .toast-icon { color: var(--success); }
.toast.error .toast-icon { color: var(--error); }
.toast.warning .toast-icon { color: var(--warning); }
.toast.info .toast-icon { color: var(--primary); }

/* 动画 */
.toast-container.bottom-right .toast {
  animation: slide-in-right 0.3s ease;
}

.toast-container.top-right .toast {
  animation: slide-in-top 0.3s ease;
}

@keyframes slide-in-right {
  from {
    transform: translateX(120%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

@keyframes slide-in-top {
  from {
    transform: translateY(-120%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

/* 其他样式 */
.toast-icon {
  margin-right: 0.75rem;
  font-size: 1.2rem;
}

.toast-content {
  flex-grow: 1;
  min-width: 0;
}

.toast-title {
  font-weight: bold;
  margin-bottom: 0.25rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.toast-message {
  color: var(--text-secondary);
  font-size: 0.9rem;
  line-height: 1.4;
}

.toast-close {
  background: none;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  padding: 0.25rem;
  margin-left: 0.5rem;
  flex-shrink: 0;
}

.toast-close:hover {
  color: var(--text-primary);
}
</style>



